package cn.bmbanjia.zebra2024.frame.validation;

import cn.hutool.core.util.IdcardUtil;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 类说明:身份证合法性校验
 * 18位身份证号码：第7、8、9、10位为出生年份(四位数)，第11、第12位为出生月份，第13、14位代表出生日期，第17位代表性别，奇数为男，偶数为女。
 */
@Slf4j
public class IdNumberValidator implements ConstraintValidator<IdNumber, String> {

    // 每位加权因子
    private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};

    /**
     * 将15位的身份证转成18位身份证
     *
     * @param idcard x
     * @return x
     */
    public static String convertIdcarBy15bit(String idcard) {
        String idcard17;
        // 非15位身份证
        if (idcard.length() != 15) {
            return null;
        }

        if (isDigital(idcard)) {
            // 获取出生年月日
            String birthday = idcard.substring(6, 12);
            Date birthdate;
            try {
                birthdate = new SimpleDateFormat("yyMMdd").parse(birthday);
            } catch (ParseException e) {
                log.error("ParseException", e);
                return null;
            }
            Calendar cday = Calendar.getInstance();
            cday.setTime(birthdate);
            String year = String.valueOf(cday.get(Calendar.YEAR));

            idcard17 = idcard.substring(0, 6) + year + idcard.substring(8);

            char[] c = idcard17.toCharArray();
            String checkCode;

            int[] bit;

            // 将字符数组转为整型数组
            bit = converCharToInt(c);
            int sum17;
            sum17 = getPowerSum(bit);

            // 获取和值与11取模得到余数进行校验码
            checkCode = getCheckCodeBySum(sum17);
            // 获取不到校验位
            if (null == checkCode) {
                return null;
            }

            // 将前17位与第18位校验码拼接
            idcard17 += checkCode;
        } else { // 身份证包含数字
            return null;
        }
        return idcard17;
    }

    /**
     * @param idcard x
     * @return x
     */
    public static boolean isValidate18Idcard(String idcard) {
        // 非18位为假
        if (idcard.length() != 18) {
            return false;
        }
        // 获取前17位
        String idcard17 = idcard.substring(0, 17);
        // 获取第18位
        String idcard18Code = idcard.substring(17, 18);
        char[] c;
        String checkCode;
        // 是否都为数字
        if (isDigital(idcard17)) {
            c = idcard17.toCharArray();
        } else {
            return false;
        }

        int[] bit;

        bit = converCharToInt(c);

        int sum17;

        sum17 = getPowerSum(bit);

        // 将和值与11取模得到余数进行校验码判断
        checkCode = getCheckCodeBySum(sum17);
        if (null == checkCode) {
            return false;
        }
        // 将身份证的第18位与算出来的校码进行匹配，不相等就为假
        return idcard18Code.equalsIgnoreCase(checkCode);
    }

    /**
     * 数字验证
     *
     * @param str x
     * @return x
     */
    public static boolean isDigital(String str) {
        return str != null && !str.isEmpty() && str.matches("^[0-9]*$");
    }

    public static int getPowerSum(int[] bit) {

        int sum = 0;

        if (power.length != bit.length) {
            return sum;
        }

        for (int i = 0; i < bit.length; i++) {
            for (int j = 0; j < power.length; j++) {
                if (i == j) {
                    sum = sum + bit[i] * power[j];
                }
            }
        }
        return sum;
    }

    /**
     * 将和值与11取模得到余数进行校验码判断
     *
     * @param sum17 x
     * @return 校验位
     */
    public static String getCheckCodeBySum(int sum17) {
        return switch (sum17 % 11) {
            case 10 -> "2";
            case 9 -> "3";
            case 8 -> "4";
            case 7 -> "5";
            case 6 -> "6";
            case 5 -> "7";
            case 4 -> "8";
            case 3 -> "9";
            case 2 -> "x";
            case 1 -> "0";
            case 0 -> "1";
            default -> null;
        };
    }

    /**
     * 将字符数组转为整型数组
     *
     * @param c x
     * @return x
     * @throws NumberFormatException x
     */
    public static int[] converCharToInt(char[] c) throws NumberFormatException {
        int[] a = new int[c.length];
        int k = 0;
        for (char temp : c) {
            a[k++] = Integer.parseInt(String.valueOf(temp));
        }
        return a;
    }

    @Override
    public boolean isValid(String idNumber, ConstraintValidatorContext constraintValidatorContext) {
        return IdcardUtil.isValidCard(idNumber);

        // 日期
//        if (idNumber.length() == 15) {
//            idNumber = convertIdcarBy15bit(idNumber);
//        }
//        if (idNumber == null) {
//            return false;
//        }
//        return isValidate18Idcard(idNumber);
    }

}
